package com.ccc.dingtalk.service.dingtalk.impl;

import cn.hutool.core.date.DateUtil;
import com.ccc.dingtalk.config.CompanyProperties;
import com.ccc.dingtalk.constant.CheckTypeEnum;
import com.ccc.dingtalk.constant.TimeResultEnum;
import com.ccc.dingtalk.pojo.db.UserInfo;
import com.ccc.dingtalk.pojo.dingtalk.DingUser;
import com.ccc.dingtalk.pojo.vo.AttendanceRecordresultVO;
import com.ccc.dingtalk.pojo.vo.UserAttendanceVO;
import com.ccc.dingtalk.service.db.IUserInfoService;
import com.ccc.dingtalk.service.dingtalk.AttendanceService;
import com.ccc.dingtalk.service.dingtalk.TokenService;
import com.ccc.dingtalk.service.dingtalk.UserService;
import com.ccc.dingtalk.util.DingtalkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author superC
 * @version 1.0.0
 * @date 2023-08-25
 */

@Service
public class AttendanceServiceImpl implements AttendanceService {
    protected static final Logger logger = LoggerFactory.getLogger(AttendanceServiceImpl.class);

    @Autowired
    private CompanyProperties companyProperties;

    @Autowired
    private DingtalkUtil dingtalkUtil;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserService userService;

    @Autowired
    private IUserInfoService userInfoService;

    @Override
    public List<UserAttendanceVO> getTodayAttendanceList2AllUser() throws Exception {
        logger.info("【调用接口】-> 获取今天所有员工的考勤打卡列表");
        // 1. 获取token
        String accessToken = tokenService.getAccessToken();

        // 2. 根据所有用户，先从DB中获取
        List<UserInfo> userInfoList = userInfoService.findAll();
        if (!userInfoList.isEmpty()) {
            return this.getAllAttendanceList2DbUser(accessToken, userInfoList);
        } else {
            // 从钉钉获取用户，再获取考勤打卡数据
            List<DingUser> userList = userService.getAllUsersAndStoreDb(accessToken);
            return this.getAllAttendanceList(accessToken, userList);
        }
    }

    /**
     * 获取考勤打卡数据
     */
    private List<UserAttendanceVO> getAllAttendanceList(String accessToken, List<DingUser> userList) throws Exception {
        List<UserAttendanceVO> noClockList = new ArrayList<>();
        List<UserAttendanceVO> clockList = new ArrayList<>();
        String today = DateUtil.today();
        String workDateFrom = today + companyProperties.getOnTime();
        String workDateTo = today + companyProperties.getOffTime();

        List<String> allUserIds = userList.stream().map(DingUser::getUserid).collect(Collectors.toList());

        // 4. 获取考勤记录
        List<AttendanceRecordresultVO> attendanceList = dingtalkUtil.getAttendanceList(accessToken, workDateFrom, workDateTo, allUserIds);

        // 5. 根据全部用户，合并上班和下班打卡数据
        userList.forEach(user -> {
            // 是否上班未打卡
            AtomicBoolean isNotOnClock = new AtomicBoolean(true);
            UserAttendanceVO result = new UserAttendanceVO(user.getUserid(), user.getName());
            attendanceList.forEach(data -> {
                if (user.getUserid().equals(data.getUserId())) {
                    // 判断打卡类型并添加到对应的属性中
                    if (CheckTypeEnum.ONDUTY.getMark().equals(data.getCheckType())) {
                        result.setOnState(data.getTimeResult());
                        result.setOnStateName(data.getTimeResultName());
                        // 上班打卡，状态不是“未打卡”
                        if (!TimeResultEnum.NOTSIGNED.getMark().equals(data.getTimeResult())) {
                            result.setOnClockTime(data.getUserCheckTime());
                            isNotOnClock.set(false);
                        }
                    } else if (CheckTypeEnum.OFFDUTY.getMark().equals(data.getCheckType())) {
                        result.setOffState(data.getTimeResult());
                        result.setOffStateName(data.getTimeResultName());
                        result.setOffClockTime(data.getUserCheckTime());
                    }
                }
            });
            if (isNotOnClock.get()) {
                // 赋值当前用户上班未打卡状态
                result.setOnState(TimeResultEnum.NOTSIGNED.getMark());
                result.setOnStateName(TimeResultEnum.NOTSIGNED.getLabel());
                noClockList.add(result);
            } else {
                clockList.add(result);
            }
        });

        List<UserAttendanceVO> allList = new ArrayList<>(userList.size());
        // 未打卡员工放在列表最前面
        allList.addAll(noClockList);
        if (!clockList.isEmpty()) {
            // 打卡员工按打卡时间倒排
            clockList.sort(Comparator.comparing(UserAttendanceVO::getOnClockTime).reversed());
            allList.addAll(clockList);
        }
        return allList;
    }

    /**
     * 从DB中获取到user，再获取考勤打卡数据
     */
    private List<UserAttendanceVO> getAllAttendanceList2DbUser(String accessToken, List<UserInfo> userInfoList) throws Exception {
        List<UserAttendanceVO> noClockList = new ArrayList<>();
        List<UserAttendanceVO> clockList = new ArrayList<>();
        String today = DateUtil.today();
        String workDateFrom = today + companyProperties.getOnTime();
        String workDateTo = today + companyProperties.getOffTime();

        List<String> allUserIds = userInfoList.stream().map(UserInfo::getId).collect(Collectors.toList());

        // 4. 获取考勤记录
        List<AttendanceRecordresultVO> attendanceList = dingtalkUtil.getAttendanceList(accessToken, workDateFrom, workDateTo, allUserIds);

        // 5. 根据全部用户，合并上班和下班打卡数据
        userInfoList.forEach(user -> {
            // 是否上班未打卡
            AtomicBoolean isNotOnClock = new AtomicBoolean(true);
            UserAttendanceVO result = new UserAttendanceVO(user.getId(), user.getName());
            attendanceList.forEach(data -> {
                if (user.getId().equals(data.getUserId())) {
                    // 判断打卡类型并添加到对应的属性中
                    if (CheckTypeEnum.ONDUTY.getMark().equals(data.getCheckType())) {
                        result.setOnState(data.getTimeResult());
                        result.setOnStateName(data.getTimeResultName());
                        // 上班打卡，状态不是“未打卡”
                        if (!TimeResultEnum.NOTSIGNED.getMark().equals(data.getTimeResult())) {
                            result.setOnClockTime(data.getUserCheckTime());
                            isNotOnClock.set(false);
                        }
                    } else if (CheckTypeEnum.OFFDUTY.getMark().equals(data.getCheckType())) {
                        result.setOffState(data.getTimeResult());
                        result.setOffStateName(data.getTimeResultName());
                        result.setOffClockTime(data.getUserCheckTime());
                    }
                }
            });
            if (isNotOnClock.get()) {
                // 赋值当前用户上班未打卡状态
                result.setOnState(TimeResultEnum.NOTSIGNED.getMark());
                result.setOnStateName(TimeResultEnum.NOTSIGNED.getLabel());
                noClockList.add(result);
            } else {
                clockList.add(result);
            }
        });

        List<UserAttendanceVO> allList = new ArrayList<>(userInfoList.size());
        // 未打卡员工放在列表最前面
        allList.addAll(noClockList);
        if (!clockList.isEmpty()) {
            // 打卡员工按打卡时间倒排
            clockList.sort(Comparator.comparing(UserAttendanceVO::getOnClockTime).reversed());
            allList.addAll(clockList);
        }
        return allList;
    }

    @Override
    @Deprecated
    public List<UserAttendanceVO> getTodayAttendanceList2UserGroup2() throws Exception {
        Map<String, UserAttendanceVO> resultMap = getTodayAttendanceList2UserGroup();
        // 将map的值转换为list
        return new ArrayList<>(resultMap.values());
    }

    @Override
    public Map<String, UserAttendanceVO> getTodayAttendanceList2UserGroup() throws Exception {
        Map<String, UserAttendanceVO> resultMap = new LinkedHashMap<>();
        List<AttendanceRecordresultVO> list = getTodayAttendanceList();
        list.forEach(data -> {
            String userId = data.getUserId();

            // 如果用户ID不存在于合并数据的Map中，则创建一个新的UserData对象进行存储
            if (!resultMap.containsKey(userId)) {
                resultMap.put(userId, new UserAttendanceVO(userId, data.getUserName()));
            }
            UserAttendanceVO userVo = resultMap.get(userId);
            // 判断打卡类型并添加到对应的属性中
            if (CheckTypeEnum.ONDUTY.getMark().equals(data.getCheckType())) {
                userVo.setOnState(data.getTimeResult());
                userVo.setOnStateName(data.getTimeResultName());
                userVo.setOnClockTime(data.getUserCheckTime());
            } else if (CheckTypeEnum.OFFDUTY.getMark().equals(data.getCheckType())) {
                userVo.setOffState(data.getTimeResult());
                userVo.setOffStateName(data.getTimeResultName());
                userVo.setOffClockTime(data.getUserCheckTime());
            }
            resultMap.put(userId, userVo);
        });
        return resultMap;
    }

    @Override
    public List<AttendanceRecordresultVO> getTodayAttendanceList() throws Exception {
        String today = DateUtil.today();
        String workDateFrom = today + companyProperties.getOnTime();
        String workDateTo = today + companyProperties.getOffTime();
        return getAttendanceList(workDateFrom, workDateTo);
    }

    @Override
    public List<AttendanceRecordresultVO> getAttendanceList(String workDateFrom, String workDateTo) throws Exception {
        logger.info("【调用接口】-> 获取指定日期的考勤打卡列表");
        // 1. 获取token
        String accessToken = tokenService.getAccessToken();

        // 2. 获取用户ID集
        List<String> allUserIds = userService.getAllUserIds(accessToken);

        // 3. 获取考勤记录
        return dingtalkUtil.getAttendanceList(accessToken, workDateFrom, workDateTo, allUserIds);
    }

}
